今天稍微提一下 design patterns 的分類,
也看看設計模式:Prototype, Singleton, Facade 的 Go 程式碼
ㄚ,Prototype 的 Go 實作細節沒看懂,之後有機會再補吧
Design patterns 可以分為三大類:Creational / Structural / Behavioral,
雖然看了解釋但感受還沒那麼深,可參考 The Catalog of Design Patterns
其中這幾天,提到的都是 creational 類型的 design patterns,
而今天只有 Facade 是 behavioral。
複製已經存在的物件,然後稍微改一點東西。
[Design Pattern] Prototype 原型模式 這邊提到 Prototype Pattern 非常適合用在有深層結構而且高度自定義的物件上面,在這種情況下你通常不會想從頭建立這些物件,另一方面也可以提高程式碼的可讀性。
Go 實作 07_prototype 還沒看很懂,先不放上來了
確保一個 class 只能產生一個 instance
可能要存取某個共享的資源,例如資料庫或檔案。
Go 沒有物件,用大寫表示 public 小寫表示 private
import "sync"
type Singleton interface {
foo()
}
type singleton struct{}
// foo 表示這個 singleton 的 private function
func (s singleton) foo() {}
// 宣告 instance
var (
instance *singleton
once sync.Once
)
// 外部可呼叫 GetInstance 獲得 singleton instance
func GetInstance() Singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
至於其他細節參考 Singleton
主要是提供一個 interface 供外界操作,但把內部複雜的子系統隱藏起來
以下面的程式碼來說,若A、B api 有更新異動,則去更改 facade 實作 apiImpl
的 Test()
。
也就是外部 client 依賴於這層 facade interface,而自己不需要知道內部子系統(A、B api)的邏輯。
本來不太理解為什麼要抽出來一層,但後來想想如果是別的程式要用那就很合理呢,如果某個功能背後會用到不同的第三方庫或工具,那寫好一個 facade interface,就能在很多地方實體化這個好懂好用的 facade,而不用每次用到類似功能還需要再理解一次這些複雜的子系統。
可以參考 Facade 中的 VideoConverter 範例
func NewAPI() API {
return &apiImpl{
a: NewAModuleAPI(),
b: NewBModuleAPI(),
}
}
//API is facade interface of facade package
type API interface {
Test() string
}
//facade implement
type apiImpl struct {
a AModuleAPI
b BModuleAPI
}
func (a *apiImpl) Test() string {
aRet := a.a.TestA()
bRet := a.b.TestB()
return fmt.Sprintf("%s\n%s", aRet, bRet)
}
這裏讓 NewAModuleAPI 是大寫,所以其實 client 也可以直接呼叫啦...或許會有這樣的需求?
B 也差不多
// ################################
//NewAModuleAPI return new AModuleAPI
func NewAModuleAPI() AModuleAPI {
return &aModuleImpl{}
}
//AModuleAPI ...
type AModuleAPI interface {
TestA() string
}
type aModuleImpl struct{}
func (*aModuleImpl) TestA() string {
return "A module running"
}